﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Threading;

namespace UnitTestUtils.UI
{
    /// <summary>
    /// Extensions to the <see cref="Dispatcher"/> class.
    /// </summary>
    public static class DispatcherExtensions
    {
        /// <summary>
        /// Actively waits and drives the dispatcher loop until either the breakCondition
        /// is true or the default timeout has expired.
        /// </summary>
        /// <param name="disp">dispatcher to wait on.</param>
        /// <param name="breakCondition"></param>
        /// <returns></returns>
        public static bool WaitOne(this Dispatcher disp, Func<bool> breakCondition)
        {
            int cycles = 0;
            int timeout = Environment.TickCount + (int)UITestHelper.GetTimeout().TotalMilliseconds;

            while (!breakCondition() && Environment.TickCount < timeout)
            {
                disp.Invoke((Action)delegate()
                {
                    ++cycles;
                }, DispatcherPriority.Background);
            }
            return breakCondition();
        }

        /// <summary>
        /// Waits for the given timespan, while running the dispatch loop.
        /// </summary>
        /// <param name="disp"></param>
        /// <param name="span"></param>
        /// <returns></returns>
        public static bool WaitOne(this Dispatcher disp, TimeSpan span)
        {
            bool elapsed = false;

            System.Threading.Timer timer = null;
            timer = new System.Threading.Timer((s) =>
                {
                    elapsed = true;
                    timer.Dispose();
                }, null, (int)span.TotalMilliseconds, 0);
            
            Func<bool> isElapsed = () => 
                {
                    return elapsed;
                };

            return WaitOne(disp, isElapsed);
        }

        /// <summary>
        /// Waits until Dispatcher queue is empty and returns.
        /// </summary>
        /// <param name="disp"></param>
        public static void Flush(this Dispatcher disp)
        {
            disp.Invoke((Action)delegate()
            {
            }, DispatcherPriority.ApplicationIdle);
        }
    }
}
